home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
WASTE 1.2
/
WASTE Demo ƒ
/
WEDemoMenus.c
< prev
next >
Wrap
Text File
|
1996-06-20
|
21KB
|
991 lines
/*
WASTE Demo Project:
Menu Handling
Copyright © 1993-1996 Marco Piovanelli
All Rights Reserved
C port by John C. Daub
*/
#ifndef __ALIASES__
#include <Aliases.h>
#endif
#ifndef __DEVICES__
#include <Devices.h>
#endif
#ifndef __LOWMEM__
#include <LowMem.h>
#endif
#ifndef __STANDARDFILE__
#include <StandardFile.h>
#endif
#ifndef __FILETYPESANDCREATORS__
#include <FileTypesAndCreators.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __WEDEMOAPP__
#include "WEDemoIntf.h"
#endif
#include "WETabs.h"
// resource types
#define kTypeMenuColorTable 'mctb'
// static variables
static MenuCRsrcHandle sColors; // handle to the 'mctb' resource for the Color menu
// constants used by DoClose()
enum {
kButtonSave = 1,
kButtonCancel,
kButtonDontSave
};
void SetDefaultDirectory( const FSSpec *spec )
{
LMSetCurDirStore( spec->parID );
LMSetSFSaveDisk( -spec->vRefNum );
}
static pascal Boolean MySFDialogFilter( DialogRef dialog, EventRecord *event, short *item, void *yourData )
{
#pragma unused ( item, yourData )
// intercept window events directed to windows behind the dialog
if ( ( event->what == updateEvt ) || ( event->what == activateEvt ) )
{
if ( (WindowRef) event->message != GetDialogWindow( dialog ) )
{
DoWindowEvent( event );
}
}
return false;
}
static ModalFilterYDUPP GetMySFDialogFilter( void )
{
#ifdef __cplusplus
static ModalFilterYDUPP sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
#else
static ModalFilterYDUPP sFilterUPP = nil;
if ( sFilterUPP == nil )
{
sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
}
#endif
return sFilterUPP;
}
short FindMenuItemText( MenuRef menu, ConstStr255Param stringToFind )
{
short item;
Str255 itemString;
for ( item = CountMItems( menu ); item >= 1; item-- )
{
GetMenuItemText( menu, item, itemString );
if ( EqualString( itemString, stringToFind, false, false ) )
break;
}
return item;
}
Boolean EqualColor( const RGBColor *rgb1, const RGBColor *rgb2 )
{
return ( (rgb1->red == rgb2->red) && (rgb1->green == rgb2->green) && (rgb1->blue == rgb2->blue) );
}
void PrepareMenus( void )
{
WindowRef window;
WEReference we;
MenuRef menu;
short item;
Str255 itemText;
long selStart, selEnd;
WEActionKind actionKind;
WEStyleMode mode;
TextStyle ts;
Boolean temp;
// get a pointer to the frontmost window, if any
window = FrontWindow();
// get associated WE instance
we = (window != nil) ? GetWindowWE(window) : nil;
// *** FILE MENU ***
menu = GetMenuHandle( kMenuFile );
// first disable all items
for ( item = CountMItems( menu); item >= 1; item-- )
DisableItem( menu, item );
// New, Open, and Quit are always enabled
EnableItem( menu, kItemNew );
EnableItem( menu, kItemOpen );
EnableItem( menu, kItemQuit );
// enable Close and Save As if there is an active window
if ( window != nil )
{
EnableItem( menu, kItemClose );
EnableItem( menu, kItemSaveAs );
// enable Save is the active window is dirty
if ( WEGetModCount( we ) > 0 )
EnableItem( menu, kItemSave );
}
// *** EDIT MENU ***
menu = GetMenuHandle( kMenuEdit );
// first, disable all items
for ( item = CountMItems( menu ); item >= 1; item-- )
DisableItem( menu, item );
// by default, the Undo menu item should read "Can't Undo"
GetIndString( itemText, kUndoStringsID, 1 );
SetMenuItemText( menu, kItemUndo, itemText );
if ( window != nil )
{
// enable Paste if there's anything pasteable on the Clipboard
if ( WECanPaste( we ) )
EnableItem( menu, kItemPaste );
// enable Undo if anything can be undone
actionKind = WEGetUndoInfo( &temp, we );
if ( actionKind != weAKNone )
{
EnableItem( menu, kItemUndo );
// change the Undo menu item to "Undo/Redo" + name of action to undo/redo
GetIndString( itemText, kUndoStringsID, 2 * actionKind + temp );
SetMenuItemText( menu, kItemUndo, itemText );
}
// enable Select All if there is anything to select
if ( WEGetTextLength( we ) > 0 )
EnableItem( menu, kItemSelectAll );
// get the current selection range
WEGetSelection( &selStart, &selEnd, we );
if ( selStart != selEnd )
{
// enable Cut, Copy, and Clear if the selection range is not empty
EnableItem( menu, kItemCut );
EnableItem( menu, kItemCopy );
EnableItem( menu, kItemClear );
}
// determine which style attributes are continuous over the current selection range
// we'll need this information in order to check the Font/Size/Style/Color menus properly
mode = weDoAll; // query about all attributes
temp = WEContinuousStyle( &mode, &ts, we );
}
else
mode = 0; // no window, so check no items
// *** FONT MENU ***
menu = GetMenuHandle( kMenuFont );
// first, remove all check marks
for ( item = CountMItems( menu ); item >= 1; item-- )
CheckItem( menu, item, false );
// if there is a continuous font all over the selection range, check the
// corresponding menu item
if ( mode & weDoFont )
{
GetFontName( ts.tsFont, itemText );
CheckItem( menu, FindMenuItemText( menu, itemText ), true );
}
// *** SIZE MENU ***
menu = GetMenuHandle( kMenuSize );
// first, remove all check marks
for ( item = CountMItems( menu ); item >= 1; item-- )
CheckItem( menu, item, false );
// if there is a continuous font size all over the selection range
// check the corresponding menu item
if ( mode & weDoSize )
{
NumToString( ts.tsSize, itemText );
CheckItem( menu, FindMenuItemText( menu, itemText ), true );
}
// *** STYLE MENU ***
menu = GetMenuHandle( kMenuStyle );
// first, remove all check marks
for ( item = CountMItems( menu ); item >= 1; item-- )
CheckItem( menu, item, false );
// check the style menu items corresponding to style attributes
if ( mode & weDoFace )
{
if ( ts.tsFace == normal )
{
CheckItem( menu, kItemPlainText, true );
}
for ( item = kItemBold; item <= kItemExtended; item++ )
{
if (ts.tsFace & ( 1 << ( item - kItemBold ) ) )
{
CheckItem( menu, item, true );
}
}
}
// *** COLOR MENU ***
menu = GetMenuHandle( kMenuColor );
// first, remove all check marks
for ( item = CountMItems( menu ); item >= 1; item-- )
CheckItem( menu, item, false );
// if there is a continuous color all over the selection range,
// check the corresponding menu item (if any )
if ( mode & weDoColor )
{
for ( item = (*sColors)->numEntries - 1; item >= 0; item-- )
{
if ( EqualColor( &ts.tsColor, & (*sColors)->mcEntryRecs[item].mctRGB2 ) )
{
CheckItem( menu, (*sColors)->mcEntryRecs[item].mctItem, true );
}
} // end for loop
}
// *** FEATURES MENU ***
menu = GetMenuHandle( kMenuFeatures );
// first remove all check marks (except the first item, which has a submenu!!)
for ( item = CountMItems( menu ); item >= 2; item-- )
CheckItem( menu, item, false );
if ( window != nil )
{
// mark each item according to the corresponding feature
if ( WEIsTabHooks( we ) )
{
CheckItem( menu, kItemTabHooks, true );
DisableItem( menu, kItemAlignment );
}
else
EnableItem( menu, kItemAlignment );
if ( WEFeatureFlag( weFAutoScroll, weBitTest, we ) )
CheckItem( menu, kItemAutoScroll, true );
if ( WEFeatureFlag( weFOutlineHilite, weBitTest, we ))
CheckItem( menu, kItemOutlineHilite, true );
if ( WEFeatureFlag( weFReadOnly, weBitTest, we ))
CheckItem( menu, kItemReadOnly, true );
if ( WEFeatureFlag( weFIntCutAndPaste, weBitTest, we ))
CheckItem( menu, kItemIntCutAndPaste, true );
if ( WEFeatureFlag( weFDragAndDrop, weBitTest, we ))
CheckItem( menu, kItemDragAndDrop, true );
if ( WEFeatureFlag( weFDrawOffscreen, weBitTest, we ) )
CheckItem( menu, kItemOffscreenDrawing, true );
}
// *** ALIGNMENT MENU ***
menu = GetMenuHandle( kMenuAlignment );
// first, remove all check marks
for ( item = CountMItems( menu ); item >= 1; item-- )
CheckItem( menu, item, false );
if ( window != nil )
{
// find the Aligment menu item corresponding to mthe current alignment state
switch ( WEGetAlignment( we ) )
{
case weFlushLeft:
item = kItemAlignLeft;
break;
case weFlushRight:
item = kItemAlignRight;
break;
case weFlushDefault:
item = kItemAlignDefault;
break;
case weCenter:
item = kItemCenter;
break;
case weJustify:
item = kItemJustify;
break;
}
// check the menu item
CheckItem( menu, item, true );
}
}
void DoDeskAcc( short menuItem )
{
Str255 deskAccessoryName;
GetMenuItemText( GetMenuHandle( kMenuApple ), menuItem, deskAccessoryName );
OpenDeskAcc( deskAccessoryName );
}
OSErr DoNew( void )
{
// create a new window from scratch
return CreateWindow( nil );
}
OSErr DoOpen( void )
{
StandardFileReply reply;
SFTypeList typeList;
OSErr err = noErr;
Point where = { -1, -1 }; // auto center dialog
// set up a list of file types we can open for StandardGetFile
typeList[0] = kTypeText;
typeList[1] = ftSimpleTextDocument;
// put up the standard open dialog box.
// (we use CustomGetFile instead of StandardGetFile because we want to provide
// our own dialog filter procedure that takes care of updating our windows)
CustomGetFile( nil, 2, typeList, &reply, 0, where, nil, GetMySFDialogFilter( ), nil, nil, nil );
// if the user ok'ed the dialog, create a new window from the specified file
if ( reply.sfGood )
err = CreateWindow( &reply.sfFile );
else
err = userCanceledErr;
return err;
}
OSErr SaveWindow( const FSSpec *pFileSpec, WindowRef window )
{
DocumentHandle hDocument;
AliasHandle alias = nil;
OSErr err;
hDocument = GetWindowDocument(window);
ForgetHandle( & (*hDocument)->fileAlias );
// save the text
if ( ( err = WriteTextFile( pFileSpec, (*hDocument)->we ) ) == noErr )
{
SetWTitle( window, pFileSpec->name );
// replace the old window alias (if any) with a new one created from pFileSpec
NewAlias( nil, pFileSpec, &alias );
// if err, alias will be nil, and it's not fatal, just will make subsequent saves annoying
(* hDocument)->fileAlias = (Handle) alias;
}
return err;
}
OSErr DoSaveAs( const FSSpec *suggestedTarget, WindowRef window )
{
StringHandle hPrompt;
Str255 defaultName;
StandardFileReply reply;
Point where = { -1, -1 }; // autocenter's dialog
OSErr err;
// get the prompt string for CustomPutFile from a string resource and lock it
hPrompt = GetString( kPromptStringID );
HLockHi( (Handle) hPrompt );
// if a suggested target file is provided, use its name as the default name
if ( suggestedTarget != nil )
{
PStringCopy( suggestedTarget->name, defaultName );
SetDefaultDirectory( suggestedTarget );
}
else
{
// otherwise use the window title as default name for CustomPutFile
GetWTitle( window, defaultName );
}
// put up the standard Save dialog box
CustomPutFile( *hPrompt, defaultName, &reply, 0, where, nil, GetMySFDialogFilter(), nil, nil, nil );
// unlock the string resource
HUnlock( (Handle)hPrompt );
// if the user ok'ed the dialog, save the window to the specified file
if ( reply.sfGood )
err = SaveWindow( &reply.sfFile, window );
else
err = userCanceledErr;
return err;
}
OSErr DoSave( WindowRef window )
{
FSSpec spec;
FSSpecPtr suggestedTarget = nil;
Boolean promptForNewFile = true;
Boolean aliasTargetWasChanged;
OSErr err;
// resolve the alias associated with this window, if any
if ( (* GetWindowDocument(window) )->fileAlias != nil )
{
if ( ( ResolveAlias( nil, (AliasHandle) (* GetWindowDocument(window))->fileAlias, &spec, &aliasTargetWasChanged ) == noErr ) )
{
if ( aliasTargetWasChanged )
suggestedTarget = &spec;
else
promptForNewFile = false;
}
}
// if no file has been previously associated with this window, or if the
// alias resolution has failed, or if the alias target was changed
// prompt the user for a new destination
if ( promptForNewFile )
err = DoSaveAs( suggestedTarget, window );
else
err = SaveWindow( &spec, window );
return err;
}
static pascal Boolean SaveChangesDialogFilter( DialogRef dialog, EventRecord *event, short *item )
{
// map command + D to the "Don't Save" button
if ( ( event->what == keyDown ) && ( event->modifiers & cmdKey ) && ( ( event->message & charCodeMask ) == 'd' ) )
{
// flash the button briefly
FlashButton( dialog, kButtonDontSave );
// fake an event in the button
*item = kButtonDontSave;
return true;
}
// route everything else to our default handler
return CallModalFilterProc( GetMyStandardDialogFilter( ), dialog, event, item );
}
OSErr DoClose( ClosingOption closing, SavingOption saving, WindowRef window )
{
Str255 s1, s2;
short alertResult;
OSErr err;
#ifdef __cplusplus
static ModalFilterUPP sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
#else
static ModalFilterUPP sFilterProc = nil;
if ( sFilterProc == nil )
{
sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
}
#endif
// is this window dirty?
if ( WEGetModCount( GetWindowWE(window) ) > 0 )
{
// do we have to ask the user whether to save changes?
if ( saving == savingAsk )
{
// prepare the parametric strings to be used in the Save Changes alert box
GetWTitle( window, s1 );
GetIndString( s2, kClosingQuittingStringsID, 1 + closing );
ParamText( s1, s2, nil, nil );
// put up the Save Changes? alert box
SetCursor( &qd.arrow );
alertResult = Alert( kAlertSaveChanges, sFilterProc );
// exit if the user canceled the alert box
if ( alertResult == kButtonCancel )
return userCanceledErr;
if ( alertResult == kButtonSave )
saving = savingYes;
else
saving = savingNo;
}
if ( saving == savingYes )
{
if ( ( err = DoSave( window ) ) != noErr )
return err;
}
}
// destroy the window
DestroyWindow( window );
return noErr;
}
OSErr DoQuit( SavingOption saving )
{
WindowRef window;
OSErr err;
// close all windows
do
{
if ( ( window = FrontWindow( ) ) != nil )
{
if ( ( err = DoClose( closingApplication, saving, window ) ) != noErr )
return err;
}
} while ( window != nil );
// set a flag so we drop out of the event loop
gExiting = true;
return noErr;
}
void DoAppleChoice( short menuItem )
{
if ( menuItem == kItemAbout )
DoAboutBox( kDialogAboutBox );
else
DoDeskAcc( menuItem );
}
void DoFileChoice( short menuItem )
{
WindowRef window = FrontWindow();
switch( menuItem )
{
case kItemNew:
DoNew( );
break;
case kItemOpen:
DoOpen( );
break;
case kItemClose:
DoClose( closingWindow, savingAsk, window );
break;
case kItemSave:
DoSave( window );
break;
case kItemSaveAs:
DoSaveAs( nil, window );
break;
case kItemQuit:
DoQuit( savingAsk );
break;
}
}
void DoEditChoice( short menuItem )
{
WindowRef window;
WEReference we;
// do nothing is no window is active
if ( ( window = FrontWindow( ) ) == nil )
return;
we = GetWindowWE(window);
switch ( menuItem )
{
case kItemUndo:
WEUndo( we );
break;
case kItemCut:
WECut( we);
case kItemCopy:
WECopy( we );
break;
case kItemPaste:
WEPaste( we );
break;
case kItemClear:
WEDelete( we );
break;
case kItemSelectAll:
WESetSelection( 0, LONG_MAX, we );
break;
}
}
void DoFontChoice( short menuItem, EventModifiers modifiers )
{
WindowRef window;
Str255 fontName;
WEStyleMode mode;
TextStyle ts;
if ( ( window = FrontWindow( ) ) != nil )
{
GetMenuItemText( GetMenuHandle( kMenuFont ), menuItem, fontName );
GetFNum( fontName, &ts.tsFont );
mode = ( modifiers & optionKey ) ? weDoFont : ( weDoFont + weDoPreserveScript + weDoExtractSubscript ) ;
WESetStyle( mode, &ts, GetWindowWE( window ) );
}
}
void DoSizeChoice( short menuItem )
{
WindowRef window;
Str255 sizeString;
long size;
WEStyleMode mode;
TextStyle ts;
if ( ( window = FrontWindow ( ) ) != nil )
{
if ( menuItem <= kItemLastSize )
{
GetMenuItemText( GetMenuHandle( kMenuSize ), menuItem, sizeString );
StringToNum( sizeString, &size );
mode = weDoSize;
ts.tsSize = size;
}
else if ( menuItem == kItemSmaller )
{
mode = weDoAddSize;
ts.tsSize = -1;
}
else if ( menuItem == kItemLarger )
{
mode = weDoAddSize;
ts.tsSize = +1;
}
WESetStyle( mode, &ts, GetWindowWE( window ) );
}
}
void DoStyleChoice( short menuItem )
{
WindowRef window;
TextStyle ts;
if ( ( window = FrontWindow( ) ) != nil )
{
switch( menuItem )
{
case kItemPlainText:
ts.tsFace = normal;
break;
case kItemBold:
case kItemItalic:
case kItemUnderline:
case kItemOutline:
case kItemShadow:
case kItemCondensed:
case kItemExtended:
ts.tsFace = 1 << ( menuItem - kItemBold );
break;
}
WESetStyle( weDoFace + weDoToggleFace, &ts, GetWindowWE( window ) );
}
}
void DoColorChoice( short menuItem )
{
WindowRef window;
short i;
TextStyle ts;
// do nothing if there is no front window
if ( ( window = FrontWindow( ) ) == nil )
return;
// find the color corresponding to the chosen menu item
for ( i = (*sColors)->numEntries - 1; i >= 0; i-- )
{
if ( (*sColors)->mcEntryRecs[i].mctItem == menuItem )
{
ts.tsColor = (*sColors)->mcEntryRecs[i].mctRGB2;
WESetStyle( weDoColor, &ts, GetWindowWE(window) );
}
}
}
void DoAlignChoice( short menuItem )
{
WindowRef window;
WEAlignment alignment;
if ( ( window = FrontWindow( ) ) != nil )
{
switch( menuItem )
{
case kItemAlignDefault:
alignment = weFlushDefault;
break;
case kItemAlignLeft:
alignment = weFlushLeft;
break;
case kItemCenter:
alignment = weCenter;
break;
case kItemAlignRight:
alignment = weFlushRight;
break;
case kItemJustify:
alignment = weJustify;
break;
}
// set the alignment mode (this automatically redraws the text)
WESetAlignment( alignment, GetWindowWE(window) );
}
}
void DoFeatureChoice( short menuItem )
{
WindowRef window;
WEReference we;
short feature;
if ( ( window = FrontWindow( ) ) == nil )
return;
we = GetWindowWE(window);
if ( menuItem == kItemTabHooks )
{
// install or remove our custom tab hooks
if ( ! WEIsTabHooks( we ) )
{
// left-align the text (the hooks only work with left-aligned text )
WESetAlignment( weFlushLeft, we );
// install tab hooks
WEInstallTabHooks( we );
}
else
{
// remove tab hooks
WERemoveTabHooks( we );
}
// turn the cursor into a wristwatch
SetCursor( * GetCursor( watchCursor ) );
// recalculate link breaks and redraw the text
WECalText( we );
WEUpdate( nil, we );
}
else
{
switch ( menuItem )
{
case kItemAutoScroll:
feature = weFAutoScroll;
break;
case kItemOutlineHilite:
feature = weFOutlineHilite;
break;
case kItemReadOnly:
feature = weFReadOnly;
break;
case kItemIntCutAndPaste:
feature = weFIntCutAndPaste;
break;
case kItemDragAndDrop:
feature = weFDragAndDrop;
break;
case kItemOffscreenDrawing:
feature = weFDrawOffscreen;
break;
}
// toggle the specified feature
WEFeatureFlag( feature, weBitToggle, we );
}
}
void DoMenuChoice( long menuChoice, EventModifiers modifiers )
{
short menuID, menuItem;
// extract menu ID and menu item from menuChoice
menuID = HiWrd( menuChoice );
menuItem = LoWrd( menuChoice );
// dispatch on menuID
switch( menuID )
{
case kMenuApple:
DoAppleChoice( menuItem );
break;
case kMenuFile:
DoFileChoice( menuItem );
break;
case kMenuEdit:
DoEditChoice( menuItem );
break;
case kMenuFont:
DoFontChoice( menuItem, modifiers );
break;
case kMenuSize:
DoSizeChoice( menuItem );
break;
case kMenuStyle:
DoStyleChoice( menuItem );
break;
case kMenuColor:
DoColorChoice( menuItem );
break;
case kMenuFeatures:
DoFeatureChoice( menuItem );
break;
case kMenuAlignment:
DoAlignChoice( menuItem );
break;
}
HiliteMenu( 0 );
}
OSErr InitializeMenus( void )
{
OSErr err = noErr;
// build up the whole menu bar from the 'MBAR' resource
SetMenuBar( GetNewMBar( kMenuBarID ) );
// add names to the apple and Font menus
AppendResMenu( GetMenuHandle( kMenuApple ), kTypeDeskAccessory );
AppendResMenu( GetMenuHandle( kMenuFont ), kTypeFont );
// insert the alignment subment into the hierarchical portion of the menu list
InsertMenu( GetMenu( kMenuAlignment), -1 );
// disable the "Drag and Drop Editing" item in the Features menu once and for all
// if the Drag Manager isn't available
if ( ! gHasDragAndDrop )
DisableItem( GetMenuHandle( kMenuFeatures ), kItemDragAndDrop );
// load the menu color table for the color menu
sColors = (MenuCRsrcHandle)GetResource( kTypeMenuColorTable, kMenuColor );
err = ResError();
if ( err != noErr )
return err;
HNoPurge( (Handle)sColors );
// draw the menu bar
DrawMenuBar();
return err;
}